package com.yfbao.horizon.schedule.tk.common;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.apache.commons.math3.distribution.BinomialDistribution;
import org.apache.commons.math3.random.RandomGenerator;
import org.apache.commons.math3.random.RandomGeneratorFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 下面本地缓存是为了解决@Cacheable注解的远程缓存处理缓慢的问题
 * 可以根据配置参数cacheLocalRatio实现按照一定比率的数据走本地缓存
 * 目前采用所有的cacheNames全部存在一个缓存对象中，后期可根据实际情况，根据cacheName区分多个缓存存储
 */
@Component
public class LocalCacheUtil {

    /**
     * 代理的缓存名称
     */
    @Value("${cache.local.names}")
    private Set<String> cacheNamesSet;

    /**
     * 本地缓存的百分比
     */
    @Value("${cache.local.ratio}")
    private Double cacheLocalRatio;

    private static BinomialDistribution binomialDistribution =null;

    public static Cache<String, Object> localCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES)
            .maximumSize(10000)
            .recordStats().build();

    /**
     * todo： 需要替换为系统内置
     * @param cacheName
     * @param key
     * @return
     */
    public String getCompleteCacheKey(String cacheName, String key){
        return cacheName+":"+key;
    }

    public void addCache(String cacheName,String key,Object obj){
        if(!cacheNamesSet.contains(cacheName)){
            return;
        }
        if(!ifNeedCache()){
            return;
        }
        String cacheKey = getCompleteCacheKey(cacheName, key);
        localCache.put(cacheKey,obj);
    }

    public Object getCache(String cacheName,String key){
        if(!cacheNamesSet.contains(cacheName)){
            return null;
        }
        String cacheKey = getCompleteCacheKey(cacheName, key);
        return localCache.getIfPresent(cacheKey);
    }

    public void cacheEvict(String cacheName,String key){
        if(!cacheNamesSet.contains(cacheName)){
            return;
        }
        String cacheKey = getCompleteCacheKey(cacheName, key);
        localCache.invalidate(cacheKey);
    }

    private BinomialDistribution getNormalDistribution(){

        if(cacheLocalRatio ==null || cacheLocalRatio<=0){
            return null;
        }
        if(binomialDistribution !=null ){
            return binomialDistribution;
        }
        if(cacheLocalRatio>1){
            cacheLocalRatio=1d;
        }
        synchronized (cacheLocalRatio){
            // 事件概率的平方根作为均值
            RandomGenerator randomGenerator = RandomGeneratorFactory.createRandomGenerator(new Random());
            binomialDistribution = new BinomialDistribution(randomGenerator, 1, cacheLocalRatio);
        }
        return binomialDistribution;
    }

    public boolean cacheEnable(){
        if(cacheNamesSet.isEmpty() || cacheLocalRatio==0){
            return false;
        }
        return true;
    }

    private boolean ifNeedCache(){
        BinomialDistribution distribution = getNormalDistribution();
        if(distribution ==null){
            return false;
        }
        int result = distribution.sample();
        if(result>0){
            return true;
        }
        return false;
    }

}
